
from pprint import pprint
from app_sql.database import engine
from sqlalchemy.engine import reflection
from app_sql.models import Menu
from app_sql.models import Role
from app_sql.models import GeetestNode
import autopep8
from jinja2 import Template


# autopep8 是一个自动格式化 Python 代码的工具，但它不提供直接去除空白行的功能。你可以使用其他方法，比如正则表达式替换，来实现这个需求。

# 下面是一个使用 Python 的简单脚本，它读取 Python 文件，并使用正则表达式去除所有的空白行：

import re


# fields_list = [
#     {
#         "name": "id",
#         "type": "Integer",
#         "primary_key": True,
#         "field_desc": "主键",
#     },
#     {
#         "name": "role_name",
#         "type": "String",
#         "primary_key": False,
#         "field_desc": "角色名",
#     }
# ]
base_path = "./app_sql"

table_name = Menu.__tablename__
model_name = Menu.__name__


def write_code_into_file(content="", dest_path=None):
    def remove_empty_lines(content):
        # 使用正则表达式去除空行
        content_without_empty_lines = re.sub(
            r'^\s*\n', '', content, flags=re.MULTILINE)
        return content_without_empty_lines

    content = remove_empty_lines(content)
    content = autopep8.fix_code(content)
    with open(dest_path, "w", encoding="utf8") as writer:
        writer.write(content)


def create_crud_by_mode(models_object):
    table_name = models_object.__tablename__
    model_name = models_object.__name__
    insp = reflection.Inspector.from_engine(engine)
    # schema: 数据库名称
    # table_names = insp.get_table_names()
    # 表名，库名
    table_columns = insp.get_columns(table_name=table_name)

    fields_list = []
    type_choices = {
        "integer": "Integer",
        "varchar": "String",
        "boolean": "Boolean",
    }
    for item in table_columns:
        item_primary_key = False
        item_name = ""
        item_type = ""
        item_field_desc = ""
        if item.get("primary_key"):
            item_field_desc = "主键"
            item_primary_key = True
        if item.get("name"):
            item_name = item.get("name")
        if item.get("type"):
            type_str = item.get("type").__str__().lower()
            print(type_str)
            item_type = type_choices.get(type_str)
        item_dict = {
            "name": item_name,
            "type": item_type,
            "primary_key": item_primary_key,
            "field_desc": item_field_desc,
        }
        fields_list.append(item_dict)
    ######################################
    context = {
        'table_name': table_name,
        'model_name': model_name,
        'fields_list': fields_list
    }
    ######################################
    template_schemas = """
from typing import List, Union
from pydantic import BaseModel









class {{table_name}}Update(BaseModel):
    {% for item in fields_list %}
    {% if item.type == 'String'%}
    {{item.name}}: str
    {% elif item.type == 'Boolean'%}
    {{item.name}}: bool
    {% elif item.type == 'Integer' %}
    {{item.name}}: int{% endif %}
    {% endfor %}


class {{table_name}}Create(BaseModel):
    {% for item in fields_list %}
    {% if item.primary_key == true %}
    #############主键
    {% elif item.type == 'String'%}
    {{item.name}}: str{% elif item.type == 'Integer' %}
    {{item.name}}: int{% endif %}
    {% endfor %}

    
class {{table_name}}(BaseModel):{% for item in fields_list %}
    {% if item.type == 'String'%}
    {{item.name}}: str{% elif item.type == 'Integer' %}
    {{item.name}}: int{% endif %}{% endfor %}

    class Config:
        orm_mode = True
"""
    # 创建一个 Template 对象
    template = Template(template_schemas)
    # 渲染模板，并传入上下文变量
    rendered = template.render(context)
    dest_path = base_path + \
        '/demo_{table_name}_schemas.py'.format(table_name=table_name)
    write_code_into_file(content=rendered, dest_path=dest_path)

    ######################################
    template_crud = """
from sqlalchemy.orm import Session

from . import models
from . import demo_{{table_name}}_schemas as schemas

#######################################################################
{% if table_name %}

def get_{{table_name}}(db: Session, {{table_name}}_id: int):
    # 主键获取
    return db.query(models.{{model_name}}).filter(models.{{model_name}}.id == {{table_name}}_id).first()

    
def get_{{table_name}}_by_field(db: Session, field_dict: dict):
    # 条件筛选
    base_query = db.query(models.{{model_name}})
    {% for item in fields_list %}
    {{item.name}} = field_dict.get("{{item.name}}")
    if {{item.name}}:
        base_query = base_query.filter(models.{{model_name}}.{{item.name}} == {{item.name}})
    {% endfor %}

    return base_query.first()

    
def get_{{table_name}}s(db: Session, skip: int = 0, limit: int = 100):
    # 分页获取
    return db.query(models.{{model_name}}).offset(skip).limit(limit).all()


def create_{{table_name}}(db: Session, {{table_name}}: schemas.{{table_name}}Create):
    # 创建
    create_dict = {{table_name}}.dict()
    db_{{table_name}} = models.{{model_name}}(
        **create_dict
    )
    db.add(db_{{table_name}})
    db.commit()
    db.refresh(db_{{table_name}})
    return db_{{table_name}}
{% endif %}


def update_{{table_name}}(db: Session, update_{{table_name}}: schemas.{{table_name}}Update):
    # 更新
    update_dict = update_{{table_name}}.model_dump()
    model_pk = update_dict.pop("id")
    db.query(models.{{model_name}}).filter(
        models.{{model_name}}.id == model_pk).update(update_dict)
    db.commit()
    db_role = db.query(models.{{model_name}}).filter(models.{{model_name}}.id == model_pk).first()
    return db_role


def delete_{{table_name}}s(db: Session, {{table_name}}_id_list:list):
    # 删除 
    base_objects = db.query(models.{{model_name}}).filter(models.{{model_name}}.id.in_({{table_name}}_id_list))
    base_objects.delete()
    db.commit()
    return base_objects.all()
    """
    # 创建一个 Template 对象
    template = Template(template_crud)
    # 渲染模板，并传入上下文变量
    rendered = template.render(context)
    dest_path = base_path + \
        '/demo_{table_name}_crud.py'.format(table_name=table_name)
    write_code_into_file(content=rendered, dest_path=dest_path)

    template_api = """
from typing import List

from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session

from . import demo_{{table_name}}_crud as crud
from . import demo_{{table_name}}_schemas as schemas

from . import models
from .database import SessionLocal, engine

models.Base.metadata.create_all(bind=engine)

app = FastAPI()


# Dependency
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

#######################################################################
        
@app.post("/{{table_name}}/", response_model=schemas.{{table_name}})
def create_{{table_name}}({{table_name}}: schemas.{{table_name}}Create, db: Session = Depends(get_db)):
    db_{{table_name}} = crud.get_{{table_name}}_by_field(db, field_dict={{table_name}}.dict())
    if db_{{table_name}}:
        raise HTTPException(status_code=400, detail="Email already registered")
    return crud.create_{{table_name}}(db=db, {{table_name}}={{table_name}})


@app.get("/{{table_name}}/", response_model=List[schemas.{{table_name}}])
def read_{{table_name}}(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    {{table_name}}s = crud.get_{{table_name}}s(db, skip=skip, limit=limit)
    return {{table_name}}s


@app.get("/{{table_name}}/{{ '{' }}{{ table_name }}_id}", response_model=schemas.{{table_name}})
def read_user({{table_name}}_id: int, db: Session = Depends(get_db)):
    db_{{table_name}} = crud.get_{{table_name}}(db, {{table_name}}_id={{table_name}}_id)
    if db_{{table_name}} is None:
        raise HTTPException(status_code=404, detail="User not found")
    return db_{{table_name}}


@app.delete("/{{table_name}}/{{ '{' }}{{table_name}}_id}")
def delete_{{table_name}}({{table_name}}_id: str, db: Session = Depends(get_db)):
    {{table_name}}_id_list = {{table_name}}_id.split(",")
    crud.delete_{{table_name}}s(db, {{table_name}}_id_list={{table_name}}_id_list)
    return {"status": 200,"{{table_name}}_id_list": {{table_name}}_id_list}

@app.put("/{{table_name}}/", response_model=schemas.{{table_name}})
def update_{{table_name}}({{table_name}}: schemas.{{table_name}}Update, db: Session = Depends(get_db)):
    db_{{table_name}} = crud.update_{{table_name}}(db, update_{{table_name}}={{table_name}})
    if not db_{{table_name}}:
        raise HTTPException(status_code=404, detail="Not Found")
    return db_{{table_name}}
"""
    # 创建一个 Template 对象
    template = Template(template_api)
    # 渲染模板，并传入上下文变量
    rendered = template.render(context)
    dest_path = base_path + \
        '/demo_{table_name}_main.py'.format(table_name=table_name)
    write_code_into_file(content=rendered, dest_path=dest_path)


# create_crud_by_mode(Role)
create_crud_by_mode(GeetestNode)


template_page = """
import { useQuery } from '@tanstack/react-query';
import {
  Button,
  Card,
  Col,
  Form,
  Input,
  InputNumber,
  Modal,
  Popconfirm,
  Radio,
  Row,
  Select,
  Space,
} from 'antd';
import Table, { ColumnsType } from 'antd/es/table';
import { TableRowSelection } from 'antd/es/table/interface';
import { useEffect, useState } from 'react';

import orgService from '@/api/services/orgService';
import { IconButton, Iconify } from '@/components/icon';
import ProTag from '@/theme/antd/components/tag';

import { Organization } from '#/entity';

type SearchFormFieldType = Pick<Organization, 'name' | 'status'>;

export default function DemoCrud() {
  const [searchForm] = Form.useForm();
  const [organizationModalPros, setOrganizationModalProps] = useState<OrganizationModalProps>({
    formValue: {
      id: '',
      name: '',
      status: 'enable',
    },
    title: 'New',
    show: false,
    onOk: () => {
      setOrganizationModalProps((prev) => ({ ...prev, show: false }));
    },
    onCancel: () => {
      setOrganizationModalProps((prev) => ({ ...prev, show: false }));
    },
  });

  const columns: ColumnsType<Organization> = [
    { title: 'Name', dataIndex: 'name', width: 300 },
    { title: 'Order', dataIndex: 'order', align: 'center', width: 60 },
    {
      title: 'Status',
      dataIndex: 'status',
      align: 'center',
      width: 120,
      render: (status) => (
        <ProTag color={status === 'enable' ? 'success' : 'error'}>{status}</ProTag>
      ),
    },
    { title: 'Desc', dataIndex: 'desc', align: 'center', width: 300 },
    {
      title: 'Action',
      key: 'operation',
      align: 'center',
      width: 100,
      render: (_, record) => (
        <div className="flex w-full justify-center text-gray">
          <IconButton onClick={() => onEdit(record)}>
            <Iconify icon="solar:pen-bold-duotone" size={18} />
          </IconButton>
          <Popconfirm title="Delete the Organization" okText="Yes" cancelText="No" placement="left">
            <IconButton>
              <Iconify icon="mingcute:delete-2-fill" size={18} className="text-error" />
            </IconButton>
          </Popconfirm>
        </div>
      ),
    },
  ];

  // rowSelection objects indicates the need for row selection
  const rowSelection: TableRowSelection<Organization> = {
    onChange: (selectedRowKeys, selectedRows) => {
      console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
    },
    onSelect: (record, selected, selectedRows) => {
      console.log(record, selected, selectedRows);
    },
    onSelectAll: (selected, selectedRows, changeRows) => {
      console.log(selected, selectedRows, changeRows);
    },
  };

  const { data } = useQuery({
    queryKey: ['orgs'],
    queryFn: orgService.getOrgList,
  });

  const onSearchFormReset = () => {
    searchForm.resetFields();
  };

  const onCreate = () => {
    setOrganizationModalProps((prev) => ({
      ...prev,
      show: true,
      title: 'Create New',
      formValue: {
        ...prev.formValue,
        id: '',
        name: '',
        order: 1,
        desc: '',
        status: 'enable',
      },
    }));
  };

  const onEdit = (formValue: Organization) => {
    setOrganizationModalProps((prev) => ({
      ...prev,
      show: true,
      title: 'Edit',
      formValue,
    }));
  };

  return (
    <Space direction="vertical" size="large" className="w-full">
      <Card>
        <Form form={searchForm}>
          <Row gutter={[16, 16]}>
            <Col span={24} lg={6}>
              <Form.Item<SearchFormFieldType> label="Name" name="name" className="!mb-0">
                <Input />
              </Form.Item>
            </Col>
            <Col span={24} lg={6}>
              <Form.Item<SearchFormFieldType> label="Status" name="status" className="!mb-0">
                <Select>
                  <Select.Option value="enable">
                    <ProTag color="success">Enable</ProTag>
                  </Select.Option>
                  <Select.Option value="disable">
                    <ProTag color="error">Disable</ProTag>
                  </Select.Option>
                </Select>
              </Form.Item>
            </Col>
            <Col span={24} lg={12}>
              <div className="flex justify-end">
                <Button onClick={onSearchFormReset}>Reset</Button>
                <Button type="primary" className="ml-4">
                  Search
                </Button>
              </div>
            </Col>
          </Row>
        </Form>
      </Card>

      <Card
        title="Organization List"
        extra={
          <Button type="primary" onClick={onCreate}>
            New
          </Button>
        }
      >
        <Table
          rowKey="id"
          size="small"
          scroll={{ x: 'max-content' }}
          pagination={false}
          columns={columns}
          dataSource={data}
          rowSelection={{ ...rowSelection }}
        />
      </Card>

      <OrganizationModal {...organizationModalPros} />
    </Space>
  );
}

type OrganizationModalProps = {
  formValue: Organization;
  title: string;
  show: boolean;
  onOk: VoidFunction;
  onCancel: VoidFunction;
};

function OrganizationModal({ title, show, formValue, onOk, onCancel }: OrganizationModalProps) {
  const [form] = Form.useForm();
  useEffect(() => {
    form.setFieldsValue({ ...formValue });
  }, [formValue, form]);
  return (
    <Modal title={title} open={show} onOk={onOk} onCancel={onCancel}>
      <Form
        initialValues={formValue}
        form={form}
        labelCol={{ span: 4 }}
        wrapperCol={{ span: 18 }}
        layout="horizontal"
      >
        <Form.Item<Organization> label="Name" name="name" required>
          <Input />
        </Form.Item>
        <Form.Item<Organization> label="Order" name="order" required>
          <InputNumber style={{ width: '100%' }} />
        </Form.Item>
        <Form.Item<Organization> label="Status" name="status" required>
          <Radio.Group optionType="button" buttonStyle="solid">
            <Radio value="enable"> Enable </Radio>
            <Radio value="disable"> Disable </Radio>
          </Radio.Group>
        </Form.Item>
        <Form.Item<Organization> label="Desc" name="desc">
          <Input.TextArea />
        </Form.Item>
      </Form>
    </Modal>
  );
}

// export default function DemoCrud() {
//   return <Typography.Title>DemoCrud</Typography.Title>;
// }
"""
